#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
@Time    : 2019-10-09 11:30
@Author  : wangb
@Email   : joker_wb@163.com
@File    : image_utils.py
@Software: PyCharm
图片相关工具
"""
import datetime
import json
import os
import time
import cv2
import numpy as np
import multiprocessing as mp

import requests

import utils.configloader as cfg
from logger import LOG
from redis_msg_type import RedisMsgType
from src.detect_imgs import DetectImgs
from utils.date_utils import DateUtils, DataStatus

# COMMIT_MESSAGE_URL = "http://127.0.0.1:8080/smart/message/commitMessage"
COMMIT_MESSAGE_URL = cfg.get_post_message_api_url()
IMG_URL = "http://132.232.9.238/pics/"


def choose_rois(img, staff_info_in_one_camera):
    """
    根据roi把图像中的roi选择出来
    :param img:
    :param staff_info_in_one_camera:
    :return:
    """
    imgs = []
    staff_nums = []
    rois = []
    for staff in staff_info_in_one_camera.get('msg'):
        roi = staff.get('region_points')
        tmp = img[roi[1]:roi[3] + roi[1], roi[0]:roi[2] + roi[0]]
        imgs.append(tmp)
        staff_nums.append(staff.get('staff_num'))
        rois.append(roi)
    imgs.append(
        {"camera_id": staff_info_in_one_camera.get('camera_id'),
         "origin_img": img,
         "staff_nums": staff_nums,
         "rois": rois
         }
    )
    return imgs


def resize_image(image, resize_height, resize_width):
    '''
    :param image:
    :param resize_height:
    :param resize_width:
    :return:
    '''
    image_shape = np.shape(image)
    height = image_shape[0]
    width = image_shape[1]
    if (resize_height is None) and (resize_width is None):  # 错误写法：resize_height and resize_width is None
        return image
    if resize_height is None:
        resize_height = int(height * resize_width / width)
    elif resize_width is None:
        resize_width = int(width * resize_height / height)
    image = cv2.resize(image, dsize=(resize_width, resize_height))
    return image


def image_put(q_out, camera_info, staff_status, redis_client):
    """
    处理输入图像都的函数
    :param q_out:
    :param camera_info:
    :return:
    """
    LOG.info(camera_info)
    rtsp = camera_info.get('rtsp')
    cameraNum = str(camera_info.get('cameraNum'))
    # """根据相机编号，查出员工信息"""
    # staff_info_in_one_camera = find_rois_by_camera_id(cameraNum)

    cap = cv2.VideoCapture(rtsp)
    start = time.time()
    redis_read_time = time.time()
    detection_interval = cfg.detection_interval()
    update_redis_status = True
    while True:
        """
        这个循环用来判断有没有员工信息录入，如果没有录入员工信息，则不继续
        """
        staff_info_in_one_camera = find_rois_by_camera_id(cameraNum)
        if staff_info_in_one_camera.get('success'):

            if staff_status.get(cameraNum) is None:
                staff_status[cameraNum] = {}
            if not staff_status[cameraNum]:
                staff_status[cameraNum] = {}
                temp = {}
                for staff in staff_info_in_one_camera.get('msg'):
                    temp[staff.get("staff_num")] = {
                        "is_leave": False,
                        "last_appear_time": time.time()
                    }
                staff_status[cameraNum] = temp
            break
        else:
            LOG.info('等待上传所有用户的信息')
            time.sleep(5)

    while True:

        """
        处理时间问题
        """

        """
        如果redis有数据，则说明此时此刻有用户更新，处理更新即可
        """

        if redis_client.llen(cfg.user_edit()) is not 0 and update_redis_status:
            for value in redis_client.lrange(cfg.user_edit(), 0, -1):
                value = json.loads(str(value, encoding='utf-8'))
                data = value.get('data')
                """更新配置"""
                if value.get('type') == RedisMsgType.CONFIG.value:
                    # 如果时间检测间隔不为空，则更新这个。
                    if data.get('detection_interval') is not None:
                        cfg.set_value('config', 'detection_interval', data.get('detection_interval'))
                        detection_interval = cfg.detection_interval()
                        LOG.info('update detection_interval success!')
                    # # 如果修改了工作时间，则改这个
                    # if data.get("work_time") is not None:
                    #     cfg.set_value('config', 'work_time', data.get('work_time'))
                    #     LOG.info('update work_time success!')
                elif value.get('type') == RedisMsgType.UPDATE_STAFF_INFO.value:  # 更新员工信息
                    if data.get('image_id') == cameraNum:
                        for staff in staff_info_in_one_camera.get('msg'):
                            # staff = json.dumps(staff)
                            if staff['staff_num'] == data.get('staff_num'):
                                staff['staff_num'] = data.get('update_num')
                    LOG.info("update staff msg success!")
            redis_read_time = time.time()
            update_redis_status = False  # 更新完毕之后，把该检测关闭

        """防止无限循环读redis中的数据"""
        if (time.time() - redis_read_time) > 10:
            update_redis_status = True  # 把redis更新检测打开。
            redis_read_time = time.time()

        time_status = redis_client.get('time_results')
        if time_status is None:
            time_status = {
                'code': DataStatus.WORKING.value,
                'msg': 'make a false msg'
            }
        else:
            time_status = json.loads(time_status)
        if time_status.get('code') == DataStatus.WORKING.value:

            """
            检测逻辑
            """

            if (time.time() - start) > detection_interval \
                    and staff_info_in_one_camera.get('success') is True:
                if cap.read()[0]:
                    LOG.info('camera {} put a img into queues.'.format(cameraNum))
                    results = choose_rois(cap.read()[1], staff_info_in_one_camera=staff_info_in_one_camera)
                    q_out.put(results)
                else:
                    LOG.info('no video msg now,please wait!')
                    time.sleep(5)
                start = time.time()
            else:
                # time.sleep(0.05)
                cap.read()
        else:
            """把员工的状态复位"""
            staff_status[cameraNum] = {}
            temp = {}
            for staff in staff_info_in_one_camera.get('msg'):
                temp[staff.get("staff_num")] = {
                    "is_leave": False,
                    "last_appear_time": time.time()
                }
            staff_status[cameraNum] = temp
            LOG.info("rest time now ,please wait")
            time.sleep(5)


def process_imgs(mq, staff_status, redis_client):
    """
    从rtsp流中获取到图像信息，之后进行检测人物，和判断是否在工位。
    :param mq:
    :return:
    """
    di = DetectImgs()
    warning_time = cfg.warning_time()
    redis_read_time = time.time()
    update_redis_status = True
    while True:
        if redis_client.llen(cfg.user_edit()) is not 0 and update_redis_status:
            for value in redis_client.lrange(cfg.user_edit(), 0, -1):
                value = json.loads(str(value, encoding='utf-8'))
                data = value.get('data')
                if value.get('type') == RedisMsgType.CONFIG.value:
                    if data.get('warning_time') is not None:
                        cfg.set_value('config', 'warning_time', data.get('warning_time'))
                        warning_time = cfg.warning_time()
                        LOG.info("motify warning_time to {0}!".format(warning_time))
            redis_read_time = time.time()
            update_redis_status = False
        if (time.time() - redis_read_time) > 10:
            update_redis_status = True  # 把redis更新检测打开。
            redis_read_time = time.time()
        if not mq.empty():
            imgs = mq.get()
            time_start = time.time()
            LOG.info("start detect time is {}".format(time_start))
            results = di.detect(imgs)  # 获取到处理图像的信息。
            LOG.info("process {1}:detect costs {0} s".format(time.time() - time_start, mp.current_process().name))
            deal_with_detect_results(results, staff_status, warning_time)
        else:
            LOG.info("queue is empty,so sleep a little")
            time.sleep(1)


def get_init_image(rtsp, camera_num):
    """
    获取到初始化的柜台照片
    :param rtsp:
    :param camera_num:
    :return:
    """

    cap = cv2.VideoCapture(rtsp)
    interval = 0.5
    start = time.time()
    pwd = os.getcwd() + '/camera_images/'
    if not os.path.exists(pwd):
        os.makedirs(pwd)
    while True:

        try:
            img = cap.read()[1]
        except:
            return {
                "success": False,
                "msg": "rtsp path error"
            }
        if (time.time() - start) > interval:
            cv2.imwrite(pwd + str(camera_num) + '.jpg', img)
            return {
                "success": True,
                "cameraNum": camera_num,
                "img_path": pwd + str(camera_num) + '.jpg'
            }


def find_rois_by_camera_id(camera_id):
    """
    根据摄像机id 返回属于这个摄像机下面的所有员工的信息，包括摄像机号
    :param camera_id:
    :return:
    """
    try:
        with open('config/staff_config.json', 'r') as f:
            staff_infos = json.load(f)
            staff_info_in_one_camera = staff_infos.get(camera_id)

            if staff_info_in_one_camera is None:
                """说明此时还没有上传描点信息"""
                return {
                    "success": False,
                    "msg": "未上传描点信息"
                }

            if len(staff_info_in_one_camera) == 0:
                """说明此时还没有上传描点信息"""
                return {
                    "success": False,
                    "msg": "未上传描点信息"
                }
            else:

                return {
                    "success": True,
                    "msg": staff_info_in_one_camera,
                    "camera_id": camera_id
                }
    except:
        return {
            "success": False,
            "msg": "未上传描点信息"
        }


def deal_with_detect_results(detect_result, staff_status, warning_time):
    """
    进行综合判断分析员工是否离岗
    :param detect_result:
    :param staff_status:
    :param warning_time:
    :return:
    """
    camera_id = detect_result.get('camera_id')
    if camera_id is None:
        return
    staff_infos_in_one_camera = staff_status.get(camera_id)
    for staff_num, status in zip(detect_result.get('staff_nums'),
                                 detect_result.get('detect_has_person')):

        if not status:
            """如果没有检测到人"""
            last_appear_time = staff_infos_in_one_camera[staff_num].get('last_appear_time')
            if time.time() - last_appear_time > warning_time:
                """长时间不在工位了"""
                # TODO 保存图片 ，发送message
                leave_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(last_appear_time))
                send_message(img=detect_result.get('origin_img'), camera_id=camera_id,
                             staff_num=staff_num, leave_time=leave_time)
                staff_infos_in_one_camera[staff_num]['last_appear_time'] = time.time()
        else:
            staff_infos_in_one_camera[staff_num]['last_appear_time'] = time.time()

    staff_status[camera_id] = staff_infos_in_one_camera

def mk_dirs(path):
    # 年-月-日 时:分:秒
    nowTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    # 年-月-日
    dayTime = datetime.datetime.now().strftime('%Y-%m-%d')
    pwd = os.getcwd() + '/' + path + '/' + dayTime
    # 判断文件夹是否已存在
    if not os.path.exists(pwd):
        os.makedirs(pwd)
    return {
        "pwd": pwd,
        "dayTime": dayTime
    }


def send_message(img, camera_id, staff_num, leave_time):
    """
    :param img:
    :param camera_id:
    :param leave_time:
    :param staff_num:
    :return:
    """

    """1.保存图片，获取本地图片地址"""
    dir_results = mk_dirs('detect_results')
    pwd = dir_results.get('pwd')
    hourTime = datetime.datetime.now().strftime('%H:%M:%S')
    camera_msg = "-camera:" + camera_id + '-'
    img_name = hourTime + camera_msg + str(staff_num) + '.jpg'
    local_img_path = pwd + '/' + img_name

    remote_img_url = dir_results.get('dayTime') + '/' + img_name
    cv2.imwrite(local_img_path, img)
    results_data = {
        "type": 1,
        "staff_num": staff_num,
        # "image_url": IMG_URL + remote_img_url,  # 临时使用
        "image_url": local_img_path,  # 临时使用
        "record_time": leave_time
    }

    # time.sleep(0.5)  # 模拟网络延时
    headers = {
        "license": "e10adc3949ba59abbe56e057f20f883e"
    }

    try:
        requests_results = requests.post(COMMIT_MESSAGE_URL,
                                         data=json.dumps(results_data),
                                         headers=headers, timeout=1.5)
    except Exception as e:
        requests_results = e.args
    LOG.warn('send a message to host , message is {0},response is {1}'.
             format(results_data, requests_results))
